home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Experimental BBS Explossion 3
/
Experimental BBS Explossion III.iso
/
gus
/
mikmod2.zip
/
MODLOAD.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-12-02
|
8KB
|
448 lines
/*
MODLOAD.C
Or how to load a module in C. Progged by MikMak :)
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <alloc.h>
#include <mytypes.h>
#include "modload.h"
FILE *fp; // yuck... it's global
MODULEHEADER mh;
int (*SampleLoader)(int samplenr,FILE *fp,ULONG size)=NULL; // The callback sample load routine
int ml_numchn; // number of channels in use
int ml_numpat; // number of patterns used
int ml_numsmp; // number of samples used
int ml_patsiz; // size (bytecount) per pattern
char ml_songname[21]; // CSTR songname
UBYTE ml_songlength; // songlength
UBYTE ml_positions[128]; // song sequence
char *ml_modtype; // module type name
void far *ml_patlist[128]; // a list of all patterns
SAMPLEINFO ml_samples[31]; // all samples
int ml_errno=0;
char *ml_errlist[]={
"Okay",
"Error opening modfile",
"Error loading module header",
"Unknown type of module",
"Failed allocating pattern",
"EOF while loading pattern",
"Failed allocating sample",
"EOF while loading sample",
"No sample loader defined. (use ML_RegisterSampleLoader())",
"Sample load failed"
};
enum {
ERROR_OKAY=0,
ERROR_OPENING_FILE,
ERROR_LOADING_HEADER,
ERROR_NOT_A_MODULE,
ERROR_ALLOC_PATTERN,
ERROR_EOF_PATTERNS,
ERROR_ALLOC_SAMPLE,
ERROR_EOF_SAMPLE,
ERROR_NO_LOADER,
ERROR_SAMPLE_FAILED
};
char *modtypes[]={
"M.K.", // protracker
"FLT4", // startracker 4 channel
"FLT8", // startracker 8 channel
"4CHN", // fasttracker 4 channel
"6CHN", // fasttracker 6 channel
"8CHN" // fasttracker 8 channel
};
char *modtypenames[]={
"Protracker",
"Startracker",
"Startracker",
"Fasttracker",
"Fasttracker",
"Fasttracker",
"Unknown",
"Unknown",
"Unknown",
};
char modtypechannels[]={
4,4,8,4,6,8,4,6,8
};
#pragma warn -rvl
ULONG rlong(ULONG p)
/*
Motorola long -> intel long
*/
{
asm{
push ds
lds ax,p
mov dx,ds
xchg dl,dh
xchg al,ah
xchg dx,ax
pop ds
}
}
UWORD rword(UWORD p)
/*
Motorola word -> intel word
*/
{
asm{
mov ax,p
xchg al,ah
}
}
UWORD cword(UWORD *p)
{
*p=rword(*p);
}
#pragma warn +rvl
void ConvertStr(char *d,char *s,int len)
{
strncpy(d,s,len);
d[len]='\0';
}
/*
Old (amiga) noteinfo:
_____byte 1_____ byte2_ _____byte 3_____ byte4_
/ \ / \ / \ / \
0000 0000-00000000 0000 0000-00000000
Upper four 12 bits for Lower four Effect command.
bits of sam- note period. bits of sam-
ple number. ple number.
New (peecee) noteinfo:
_byte 1_ _byte 2_ __byte 3_ _byte 4_
/ \ / \ / \ / \
00000000 00000000 0000 0000 00000000
Sample note nr. zero fx fx data
Sample ranges from 0 to 31
Note number 0 means no note. ranges from 1 to 36
*/
// Periodtable for Tuning 0, Normal
UWORD pertab[36]={
856,808,762,720,678,640,604,570,538,508,480,453,
428,404,381,360,339,320,302,285,269,254,240,226,
214,202,190,180,170,160,151,143,135,127,120,113
};
void ML_ConvertPattern(UBYTE far *pattern)
/*
Translates an amiga type pattern to a pattern with note-numbers
instead of note-periods
*/
{
int t;
UBYTE a,b,c;
UWORD period;
UBYTE note;
for(t=0;t<(ml_numchn<<6);t++){
a=pattern[0];
b=pattern[1];
c=pattern[2];
period=(((UWORD)a&0xf)<<8)+b;
if(period!=0){
for(note=0;note<36;note++){
if(period==pertab[note]) break;
}
if(note==36) note=0; // couldn't find period, kill note
note++;
}
else note=0;
pattern[0]=(a&0xf0)+(c>>4);
pattern[1]=note;
pattern[2]&=0x0f;
pattern+=4;
}
}
int ML_GetModuleType(void)
/*
Determines which type of module is being loaded, and
sets the variables ml_numchn and ml_modtype accordingly.
returns 0 on error
*/
{
int t;
// find out which ID string
for(t=0;t<6;t++){
if(!memcmp(mh.magic2,modtypes[t],4)) break;
}
/* if ID string is unknown, look if magic1 and
songlength contain reasonable values and try
to find how many channels the module contains */
if(t==6){
if(mh.magic1==127 && mh.songlength<=128){
switch(mh.magic2[3]){
case '4': t=6; break;
case '6': t=7; break;
case '8': t=8; break;
default: t=-1; break;
}
}
else t=-1;
}
/* song is no good.. return error */
if(t==-1){
ml_errno=ERROR_NOT_A_MODULE;
return 0;
}
/* set global variables */
ml_numchn=modtypechannels[t]; // get number of channels
ml_modtype=modtypenames[t]; // get ascii type of mod
ml_patsiz=ml_numchn<<8; // compute size per pattern
ConvertStr(ml_songname,mh.songname,20); // make a cstr of songname
ml_songlength=mh.songlength; // copy the songlength
memcpy(ml_positions,mh.positions,128); // copy the position array
return 1;
}
int ML_LoadModuleHeader(void)
/*
Loads the module header and translates Motorola to Intel words.
sets errno and returns 0 on error.
*/
{
int t;
/* read header */
if((fread(&mh,sizeof(MODULEHEADER),1,fp)!=1)){
ml_errno=ERROR_LOADING_HEADER;
return 0;
}
/* sample info to intel format */
for(t=0;t<31;t++){
cword(&mh.samples[t].length);
cword(&mh.samples[t].reppos);
cword(&mh.samples[t].replen);
}
return 1;
}
int ML_LoadPatterns(void)
/*
Loads all patterns into the patternlist
sets errno and returns 0 on error.
*/
{
int t;
/* First, count the number of patterns */
ml_numpat=0;
for(t=0;t<128;t++){ // <-- BUGFIX... have to check ALL positions
if(mh.positions[t] > ml_numpat){
ml_numpat=mh.positions[t];
}
}
ml_numpat++;
for(t=0;t<ml_numpat;t++){
/* For each pattern, allocate a chunk
of memory and load the pattern */
if((ml_patlist[t]=farmalloc(ml_patsiz))==NULL){
ml_errno=ERROR_ALLOC_PATTERN;
return 0;
}
if(fread(ml_patlist[t],ml_patsiz,1,fp)!=1){
ml_errno=ERROR_EOF_PATTERNS;
return 0;
}
ML_ConvertPattern(ml_patlist[t]); // convert pattern
}
return 1;
}
int ML_LoadSamples(void)
/*
Loads all samples into the sampleinfo table.
sets errno and returns 0 on error
*/
{
int t;
SAMPLEINFO *d; // new sampleinfo structure
MSAMPINFO *s; // old module sampleinfo
ml_numsmp=0; // reset number of samples
s=mh.samples; // init source pointer
d=ml_samples; // init dest pointer
if(SampleLoader==NULL){
ml_errno=ERROR_NO_LOADER;
return 0;
}
for(t=0;t<31;t++){
// convert the samplename
ConvertStr(d->samplename,s->samplename,22);
/* init the sampleinfo variables and
convert the size pointers to longword format */
d->finetune=s->finetune;
d->volume=s->volume;
d->reppos=s->reppos<<1;
d->replen=s->replen<<1;
d->length=s->length<<1;
/* sample has to be loaded ? -> increase
number of samples and allocate memory and
load sample */
if(d->length!=0){
ml_numsmp++;
if(!SampleLoader(t,fp,d->length)){
ml_errno=ERROR_SAMPLE_FAILED;
return 0;
}
}
s++; // point to next source sampleinfo
d++; // point to next destiny sampleinfo
}
return 1;
}
void ML_RegisterSampleLoader(int (*Loader)(int samplenr,FILE *fp,ULONG size))
{
SampleLoader=Loader;
}
int ML_LoadModule(char *filename,FILE *ufp)
/*
Loads a module. (By filename or file-pointer).
returns 0 on error.
*/
{
int modtype;
// reset error variable
ml_errno=ERROR_OKAY;
// open module filename
if(filename!=NULL){
if((fp=fopen(filename,"rb"))==NULL){
ml_errno=ERROR_OPENING_FILE;
return 0;
}
}
else{
fp=ufp;
}
// read the module header
if(!ML_LoadModuleHeader()) return 0; // load module header
if(!ML_GetModuleType()) return 0; // get module type
if(!ML_LoadPatterns()) return 0; // read all patterns
if(!ML_LoadSamples()) return 0; // read all samples
if(filename!=NULL) fclose(fp); // close the file
return 1;
}